package ch.subgate.pongwars;

import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.view.MotionEvent;

/**
 * Created by sam on 28.01.2015.
 */
public class GameContextP2P extends GameContext {
    public boolean mOpponentIsReady;

    public boolean mIsReady;

    /** Variable to distinguish between server and client */
    public boolean mIsServer;

    /** Streaming worker thread for bluetooth match */
    private StreamThread mStreamThread;

    private float lastSentX;

    private NetworkPlayer mNetworkPlayer;

    private HumanPlayer mHumanPlayer;

    public GameContextP2P(Context context, float volume) {
        super(context, volume);
        lastSentX = -1.0f;
    } // Constructor

    @Override
    public void update() {
        if (!mIsReady || !mOpponentIsReady) { return; }

        // Get the time passed between the last cycle and this one
        long currentFrame = System.nanoTime();
        mDeltaTime = (currentFrame - mLastFrame) / 1000000000.0f;
        mLastFrame = currentFrame;

        if (timeOut > 0.0f) {
            timeOut -= mDeltaTime;
        } else {
            ball.update(mDeltaTime);
            playerBlue.update(mDeltaTime);
            playerRed.update(mDeltaTime);
            applyBounce();
            checkGoals();
            checkWin();
        } // if
    } // update

    @Override
    public boolean getGameIsRunning() { return mIsReady && mOpponentIsReady; }

    @Override
    public void initGameObjects(float paddleSize, boolean isServer) {
        mIsServer = isServer;

        // Instantiate game objects
        ball = new Ball(Constants.DIRECTION_BLUE_BEGINS);
        if (mIsServer) {
            playerRed = mNetworkPlayer = new NetworkPlayer(true, paddleSize);
            playerBlue = mHumanPlayer = new HumanPlayer(false, paddleSize);
        } else {
            playerRed = mHumanPlayer = new HumanPlayer(true, paddleSize);
            playerBlue = mNetworkPlayer = new NetworkPlayer(false, paddleSize);
        } // if
    } // initGameObjects

    @Override
    protected void checkGoals() {
        if (mIsServer) {
            if (ball.mY > Constants.DIC_BATTLEFIELD_HEIGHT) { // Ball is colliding with battlefield bottom
                goal(false);
                try {
                    mStreamThread.sendMessage(Constants.FLAG_GOAL);
                } catch (Exception e) { /* TODO */ }
            } // if
        } else {
            if (ball.mY < 0.0f) { // Ball is colliding with battlefield top
                goal(true);
                try {
                    mStreamThread.sendMessage(Constants.FLAG_GOAL);
                } catch (Exception e) { /* TODO */ }
            } // if
        } // if
    } // checkGoals

    @Override
    public void checkWin() {
        if (
                ((playerRed.mPoints >= 3) && (playerRed.mPoints - playerBlue.mPoints >= 2))
                        || ((playerBlue.mPoints >= 3) && (playerBlue.mPoints - playerRed.mPoints >= 2))) {
            timeOut = Constants.TIME_TIMEOUT;
            mIsReady = false;
            mOpponentIsReady = false;
            if (playerRed.mPoints > playerBlue.mPoints) { // red player won
                ball.reset(Constants.DIRECTION_BLUE_BEGINS);
                mMsg = Constants.RED_WIN_TEXT;
            } else { // blue player won
                ball.reset(Constants.DIRECTION_RED_BEGINS);
                mMsg = Constants.BLUE_WIN_TEXT;
            } // if
            playerRed.mPoints = 0;
            playerBlue.mPoints = 0;
            mSoundPool.play(APPLAUSE, 1.0f, 1.0f, 0, 0, 1.0f);
        } // if
    } // checkWin

    @Override
    protected void applyBounce() {
        // Battlefield bounce
        if (ball.mX > Constants.DIC_BATTLEFIELD_WIDTH - 0.5f) {
            // Ball is colliding with battlefield right
            ball.mX = Constants.DIC_BATTLEFIELD_WIDTH - 0.5f;
            ball.direction = GameHelper.mirrorDirectionXAxis(ball.direction);
            mSoundPool.play(BOUNCE_FLOOR, 1.0f, 1.0f, 0, 0, 1.0f);
        } else if (ball.mX < 0.5f) {
            // Ball is colliding with battlefield left
            ball.mX = 0.5f;
            ball.direction = GameHelper.mirrorDirectionXAxis(ball.direction);
            mSoundPool.play(BOUNCE_FLOOR, 1.0f, 1.0f, 0, 0, 1.0f);
        } // if

        // local player bounce
        if (mIsServer) {
            if (ball.mY > playerBlue.mY - 1.0f && ball.mY < playerBlue.mY + 1.0f) {
                if (
                        ball.mX > playerBlue.mX - playerBlue.mSize - 0.5f
                                && ball.mX < playerBlue.mX + playerBlue.mSize + 0.5f) {
                    int flag = Constants.FLAG_STATE;
                    if (ball.bounce(playerBlue)) {
                        mSoundPool.play(BOUNCE_RAQUET_SMASH, 1.0f, 1.0f, 0, 0, 1.0f);
                        flag |= Constants.FLAG_SUPERBOUNCE;
                    } else {
                        mSoundPool.play(BOUNCE_RAQUET_2, 1.0f, 1.0f, 0, 0, 1.0f);
                        flag |= Constants.FLAG_BOUNCE;
                    } // if
                    try {
                        mStreamThread.sendMessage(flag);
                    } catch (Exception e) { /* TODO */ }
                } // if
            } // if
        } else {
            if (ball.mY < playerRed.mY + 1.0f && ball.mY > playerRed.mY - 1.0f) {
                if (
                        ball.mX > playerRed.mX - playerRed.mSize - 0.5f
                                && ball.mX < playerRed.mX + playerRed.mSize + 0.5f) {
                    int flag = Constants.FLAG_STATE;
                    if (ball.bounce(playerRed)) {
                        mSoundPool.play(BOUNCE_RAQUET_SMASH, 1.0f, 1.0f, 0, 0, 1.0f);
                        flag |= Constants.FLAG_SUPERBOUNCE;
                    } else {
                        mSoundPool.play(BOUNCE_RAQUET_1, 1.0f, 1.0f, 0, 0, 1.0f);
                        flag |= Constants.FLAG_BOUNCE;
                    } // if
                    try {
                        mStreamThread.sendMessage(flag);
                    } catch (Exception e) { /* TODO */ }
                } // if
            } // if
        } // if
    } // applyBounce

    @Override
    public void handleInput(int action, float diX, float diY) {
        if (mIsReady && mOpponentIsReady) {
            boolean down = true;
            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
                down = false;
            } // if
            if (Math.abs(lastSentX - diX) > Constants.MAX_ERROR) {
                lastSentX = diX;
                try {
                    mStreamThread.sendMessage(Constants.FLAG_STATE);
                } catch (Exception e) { /* TODO */ }
            } // if
            mHumanPlayer.setX(diX);
            mHumanPlayer.setIsCharging(!down);
        } else {
            if (diX > Constants.MESSAGE_LEFT
                    && diX < Constants.MESSAGE_RIGHT
                    && diY > Constants.MESSAGE_TOP
                    && diY < Constants.MESSAGE_BOTTOM) {
                mIsReady = true;
                try {
                    mStreamThread.sendMessage(Constants.FLAG_READY);
                } catch (Exception e) { /* TODO */ }
            } // if
        } // if
    } // handleInput

    @Override
    public void release() {
        if (mStreamThread != null) {
            try {
                mStreamThread.sendMessage(Constants.FLAG_QUIT);
            } catch (Exception e) { /* TODO */ }

            // stop streaming thread before dying
            mStreamThread.setIsRunning(false);
            try {
                mStreamThread.join();
            } catch (InterruptedException e) {
                // do nothing
            } // try catch
        } // if
    } // release

    public void goal(boolean byBlue) {
        if (byBlue) {
            playerBlue.mPoints++;
            ball.reset(Constants.DIRECTION_RED_BEGINS);
        } else {
            playerRed.mPoints++;
            ball.reset(Constants.DIRECTION_BLUE_BEGINS);
        } // if
        playerRed.reset();
        playerBlue.reset();
        timeOut = Constants.TIME_TIMEOUT;
        mMsg = Constants.READY_TEXT;
    } // goal

    public void setSocket(BluetoothSocket socket) {
        mStreamThread = new StreamThread(socket, this, mIsServer);
        mStreamThread.setIsRunning(true);
        mStreamThread.start();
        try {
            if (mIsServer) { mStreamThread.sendMessage(Constants.FLAG_INIT); }
        } catch (Exception e) { /* TODO */ }
    } // setSocket

} // GameContextP2P
